/*
 *  Copyright (c) M2TK Project. All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package m2tk.assistant.app.ui.view;

import cn.hutool.core.util.StrUtil;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import m2tk.assistant.app.ui.model.TR290EventTableModel;
import m2tk.assistant.app.ui.model.TR290StatsTableModel;
import m2tk.assistant.app.ui.task.AsyncQueryTask;
import m2tk.assistant.app.ui.util.ComponentUtil;
import m2tk.assistant.common.InfoView;
import m2tk.assistant.common.M2TKDatabase;
import m2tk.assistant.common.domain.TR290Event;
import m2tk.assistant.common.domain.TR290Stats;
import m2tk.assistant.common.event.RefreshInfoViewRequest;
import m2tk.assistant.common.ui.RoundPanel;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.application.Application;
import org.kordamp.ikonli.fluentui.FluentUiRegularAL;
import org.kordamp.ikonli.swing.FontIcon;
import org.pf4j.Extension;

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

import static m2tk.assistant.common.ui.UIConstants.*;

@Extension(ordinal = 2)
public class TR290InfoView extends RoundPanel implements InfoView
{
    private TR290StatsTableModel statsTableModel;
    private TR290EventTableModel eventTableModel;
    private JSplitPane splitPane;
    private JScrollPane scrollPane1;
    private JScrollPane scrollPane2;

    private Application application;
    private M2TKDatabase database;
    private EventBus bus;

    private final String viewTitle = "TR 101.290";
    private final Icon viewIcon = FontIcon.of(FluentUiRegularAL.BUG_24, ICON_SIZE_L, LIGHT_BLUE);
    private volatile long lastTimestamp;
    private static final long MIN_QUERY_INTERVAL_MILLIS = 500;

    public TR290InfoView()
    {
        initUI();
    }

    private void initUI()
    {
        statsTableModel = new TR290StatsTableModel();
        eventTableModel = new TR290EventTableModel();

        JTable statsTable = createTable();
        statsTable.setModel(statsTableModel);
        statsTable.getTableHeader().setReorderingAllowed(false);
        statsTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
        statsTable.setRowSelectionAllowed(true);
        statsTable.setColumnSelectionAllowed(false);
        statsTable.getSelectionModel().addListSelectionListener(e -> {
            if (e.getValueIsAdjusting())
                return;

            int selectedRow = statsTable.getSelectedRow();
            String selectedType = statsTableModel.getTR290EventType(selectedRow);
            if (StrUtil.isEmpty(selectedType))
                hideRecordList();
            else
                queryRecentTR290Events(selectedType);
        });

        JTable eventTable = createTable();
        eventTable.setModel(eventTableModel);
        eventTable.getTableHeader().setReorderingAllowed(false);
        eventTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
        eventTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        DefaultTableCellRenderer leadingRenderer = new DefaultTableCellRenderer();
        leadingRenderer.setHorizontalAlignment(SwingConstants.LEADING);

        TableColumnModel columnModel = statsTable.getColumnModel();
        ComponentUtil.configTableColumn(columnModel, 0, 40, false);  // 状态
        ComponentUtil.configTableColumn(columnModel, 1, leadingRenderer, 220, false); // 错误名称
        ComponentUtil.configTableColumn(columnModel, 2, leadingRenderer, 100, false); // 错误数
        ComponentUtil.configTableColumn(columnModel, 3, leadingRenderer, 220, false); // 最近发生时间
        ComponentUtil.configTableColumn(columnModel, 4, leadingRenderer, 500, true);  // 错误描述

        columnModel = eventTable.getColumnModel();
        ComponentUtil.configTableColumn(columnModel, 0, leadingRenderer, 80, false);  // 序号
        ComponentUtil.configTableColumn(columnModel, 1, leadingRenderer, 220, false); // 发生时间
        ComponentUtil.configTableColumn(columnModel, 2, leadingRenderer, 150, false); // PID
        ComponentUtil.configTableColumn(columnModel, 3, leadingRenderer, 200, false); // 位置
        ComponentUtil.configTableColumn(columnModel, 4, leadingRenderer, 500, true);  // 错误描述

        scrollPane1 = createScrollPane(statsTable);
        scrollPane2 = createScrollPane(eventTable);
        splitPane = createVerticalSplitPane(scrollPane1, scrollPane2);

        setLayout(new MigLayout("insets 10", "[][grow][]", "[25!][pref!][][grow]"));
        add(new JLabel(viewTitle,
                       FontIcon.of(FluentUiRegularAL.BUG_20, ICON_SIZE_S, LIGHT_BLUE),
                       SwingConstants.TRAILING),
            "left");
        add(createControlButton(FontIcon.of(FluentUiRegularAL.DELETE_20, ICON_SIZE_S, LIGHT_BLUE),
                                e ->
                                {
                                    database.clearTR290Events();
                                    statsTableModel.update(new TR290Stats());
                                    scrollPane2.setVisible(false);
                                    splitPane.setDividerLocation(1.0);
                                }),
            "skip, wrap");
        add(separator(), "span 3, grow, wrap");
        add(splitPane, "span 3 2, grow");

        hideRecordList();

        addComponentListener(new ComponentAdapter()
        {
            @Override
            public void componentShown(ComponentEvent e)
            {
                if (database != null)
                    queryTR290Events();
            }
        });
    }

    @Override
    public void setupApplication(Application application)
    {
        this.application = application;
    }

    @Override
    public void setupDataSource(EventBus bus, M2TKDatabase database)
    {
        this.bus = bus;
        this.database = database;

        bus.register(this);
    }

    @Override
    public JComponent getViewComponent()
    {
        return this;
    }

    @Override
    public String getViewTitle()
    {
        return viewTitle;
    }

    @Override
    public Icon getViewIcon()
    {
        return viewIcon;
    }

    @Subscribe
    public void onRefreshInfoViewEvent(RefreshInfoViewRequest event)
    {
        long t1 = System.currentTimeMillis();
        if (t1 - lastTimestamp >= MIN_QUERY_INTERVAL_MILLIS && isShowing())
        {
            queryTR290Events();
            lastTimestamp = System.currentTimeMillis();
        }
    }

    private void queryTR290Events()
    {
        Supplier<TR290Stats> query = () -> database.getTR290Stats();
        Consumer<TR290Stats> consumer = statsTableModel::update;

        AsyncQueryTask<TR290Stats> task = new AsyncQueryTask<>(application, query, consumer);
        task.execute();
    }

    private void queryRecentTR290Events(String type)
    {
        Supplier<List<TR290Event>> query = () -> database.listTR290Events(type, 100);
        Consumer<List<TR290Event>> consumer = events -> {
            eventTableModel.update(events);
            showRecordList();
        };

        AsyncQueryTask<List<TR290Event>> task = new AsyncQueryTask<>(application, query, consumer);
        task.execute();
    }

    private void hideRecordList()
    {
        scrollPane2.setVisible(false);
        splitPane.setDividerLocation(1.0);
    }

    private void showRecordList()
    {
        scrollPane2.setVisible(true);
        splitPane.setDividerLocation(0.6);
    }
}
